/*
 * Copyright (c) 2020-2099 the original author or authors. All rights reserve.
 */
package org.tianyun.cloud.security.token.strategy;

import org.apache.commons.lang3.StringUtils;
import org.tianyun.cloud.security.configuration.SecurityProperties;
import org.tianyun.cloud.security.configuration.SecurityProperties.YamlStandardTokenStrategy;
import org.tianyun.cloud.security.token.common.Authentication;
import org.tianyun.cloud.security.token.store.TokenStore;
import org.tianyun.cloud.utils.CryptBuilder;
import org.tianyun.cloud.utils.JsonUtils;

import java.security.Principal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.Map;

/**
 * Standard token strategy，默认实现，token为aes加密后的密串
 *
 * @auther ebert_chan
 */
public class StandardTokenStrategy extends AbstractTokenStrategy {

    /**
     * @param securityProperties
     * @param tokenStore
     */
    public StandardTokenStrategy(SecurityProperties securityProperties, TokenStore tokenStore) {
        super(securityProperties, tokenStore);
    }

    private static final String TOKEN_PRINCIPAL = "principal";

    private static final String TOKEN_NONCE = "nonce";

    /*
     * @see org.tianyun.cloud.security.token.strategy.AbstractTokenStrategy#generateToken(org.tianyun.cloud.security.token.common.Authentication)
     */
    @Override
    public String generateToken(Authentication authentication) {
        Map<String, Object> tokenRowValue = new HashMap<>();
        tokenRowValue.put(TOKEN_PRINCIPAL, authentication.getName());
        tokenRowValue.put(TOKEN_NONCE, LocalDateTime.now().atZone(ZoneId.systemDefault()).toEpochSecond());
        String text = JsonUtils.toJsonString(tokenRowValue);

        YamlStandardTokenStrategy yamlStandardTokenStrategy = getSecurityProperties().getTokenStrategy().getStandard();
        String value = CryptBuilder.aes().encrypt(text, yamlStandardTokenStrategy.getKey(), yamlStandardTokenStrategy.getIv());

        return value;
    }

    /*
     * @see org.tianyun.cloud.security.token.service.impl.AbstractTokenStrategy#extractToken(java.lang.String)
     */
    @Override
    public Principal extractToken(String value) {
        String name = null;
        try {
            YamlStandardTokenStrategy yamlStandardTokenStrategy = getSecurityProperties().getTokenStrategy().getStandard();
            String decryptValue = CryptBuilder.aes().decrypt(value, yamlStandardTokenStrategy.getKey(), yamlStandardTokenStrategy.getIv());
            Map<String, Object> tokenRowValue = JsonUtils.parse(decryptValue, Map.class);
            name = (String) tokenRowValue.get(TOKEN_PRINCIPAL);
        } catch (Throwable e) {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("token decrypt exception", e);
            }
        }

        if (StringUtils.isBlank(name)) {
            return null;
        }

        final String principal = name;

        return () -> principal;
    }

}
